<?php

namespace App\Services;

use App\Exceptions\BusinessException;
use App\Models\BaseModel;
use App\Models\Camp;
use App\Models\Combo;
use App\Models\Food;
use App\Models\Label;
use App\Models\Lease;
use App\Models\Notice;
use App\Models\Order;
use App\Models\PreTime;
use App\Models\User;
use DateInterval;
use DatePeriod;
use DateTime;
use Exception;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Support\Facades\DB;

class OrderService extends BaseService
{
    /**
     * 美食购物车
     * @param $cartJson
     * @return array
     * @throws BusinessException
     */
    public function foodCart($cartJson)
    {
        $cartArr = json_decode($cartJson, true);
        if (empty($cartArr)) {
            $this->throwBusinessException('请选择美食');
        }

        $foodIds = array_column($cartArr, 'food_id');
        $foodNums = array_column($cartArr, 'num', 'food_id');
        $foodRemarks = array_column($cartArr, 'remark', 'food_id');

        // 件数
        $data['count'] = count($foodIds);
        // 美食列表
        $data['food_list'] = Food::query()
            ->whereIn('id', $foodIds)
            ->get(['id', 'food_name', 'food_desc', 'food_img', 'food_price', 'label_ids', 'stock', 'status'])
            ->toArray();
        // 实际支付
        $data['pay_price'] = 0;
        $labelNames = Label::query()->pluck('label_name', 'id') ?? [];
        foreach ($data['food_list'] as &$item) {
            if ($item['stock'] < $foodNums[$item['id']]) {
                $this->throwBusinessException($item['food_name'] . '已售罄');
            }
            if ($item['status'] != BaseModel::STATUS_ENABLE) {
                $this->throwBusinessException($item['food_name'] . '已下架');
            }
            // 图片
            $item['food_img'] = storageFirst($item['food_img']);
            // 标签
            $labelIds = !empty($item['label_ids']) ? explode(',', $item['label_ids']) : [];
            $item['label_name'] = [];
            foreach ($labelIds as $labelId) {
                $item['label_name'][] = $labelNames[$labelId] ?? '';
            }
            $item['num'] = $foodNums[$item['id']] ?? 1;
            $item['remark'] = $foodRemarks[$item['id']] ?? 1;
            $data['pay_price'] = bcadd($data['pay_price'], bcmul($item['food_price'], $item['num'], 2), 2);
        }
        return $data;
    }

    /**
     * 订单预览
     * @param $uid
     * @param $sellType
     * @param $sellId
     * @param $preNum
     * @return array
     */
    public function orderPreview($uid, $sellType, $sellId, $preNum)
    {
        // 可预约时间
        $data['date_list'] = self::getPreTime($sellType, $sellId, $price);
        // 实际支付
        $data['pay_price'] = bcmul($price, $preNum, 2);
        return $data;
    }

    /**
     * 下单
     * @param $uid
     * @param $sellType
     * @param $sellId
     * @param $preNum
     * @param $preDate
     * @param $preTime
     * @param $cartJson
     * @param $phone
     * @return int
     */
    public function palaceOrder($uid, $sellType, $sellId, $preNum, $preDate, $preTime, $cartJson, $phone)
    {
        if (in_array($sellType, [Order::SELL_CAMP, Order::SELL_LEASE, Order::SELL_COMBO])) {
            // 根据 sellType 查询售卖对象
            switch ($sellType) {
                case Order::SELL_LEASE:
                    $field = ['id', 'lease_name as name', 'lease_desc as desc', 'lease_img as img', 'lease_price as price', 'label_ids', 'end_time'];
                    $result = Lease::query()->where(['id' => $sellId, 'status' => BaseModel::STATUS_ENABLE])->first($field);
                    break;
                case Order::SELL_COMBO:
                    $field = ['id', 'combo_name as name', 'combo_desc as desc', 'combo_img as img', 'combo_price as price', 'label_ids', 'end_time', 'combo_con'];
                    $result = Combo::query()->where(['id' => $sellId, 'status' => BaseModel::STATUS_ENABLE])->first($field);
                    break;
                default:
                    $field = ['id', 'camp_name as name', 'camp_desc as desc', 'camp_img as img', 'camp_price as price', 'label_ids', 'end_time'];
                    $result = Camp::query()->first($field); // 注意：硬编码 id=1
                    break;
            }
            if (!$result) {
                $this->throwBusinessException(Order::sellTypeMap()[$sellType] . '已下架');
            }
            $sellArr = $result->toArray();

            // 判断预约时间库存
            if (in_array($sellType, [Order::SELL_LEASE, Order::SELL_COMBO])) {
                $canPre = $this->getPreTime($sellType, $sellId, $price, 2);
                $this->checkStock($canPre, $preDate, $preTime, $preNum);
            }
            $price = $sellArr['price'];

            // 组装售卖对象
            $sellArr['img'] = explode(',', $sellArr['img'])[0] ?? '';
            $labelNames = Label::query()->pluck('label_name', 'id') ?? [];
            $labelIds = !empty($sellArr['label_ids']) ? explode(',', $sellArr['label_ids']) : [];
            $sellArr['label_name'] = [];
            foreach ($labelIds as $labelId) {
                $sellArr['label_name'][] = $labelNames[$labelId] ?? '';
            }
            $sellArr['end_time'] = date('Y-m-d 23:59:59', strtotime($sellArr['end_time']));

            // 套餐详情
            if ($sellType == Order::SELL_COMBO) {
                $comboCon = json_decode($sellArr['combo_con'], true);
                unset($sellArr['combo_con']);

                $sellMulti = $this->setComboCon($comboCon);
            }

            $payPrice = bcmul($price, $preNum, 2);
            $phone = User::query()->where(['id' => $uid])->value('phone') ?? '';
        } else {
            $foodCart = $this->foodCart($cartJson);
            $sellMulti = $this->setFoodList($foodCart['food_list']);
            $sellArr = $sellMulti[0];
            $sellId = $sellArr['id'];
            $preNum = $sellArr['num'];
            $payPrice = $foodCart['pay_price'];
        }

        DB::beginTransaction();
        try {
            // 下单
            $data = [
                'user_id' => $uid,
                'sell_type' => $sellType,
                'sell_id' => $sellId,
                'order_sn' => Order::getSn(),
                'pay_price' => $payPrice,
                'phone' => $phone,
                'pre_num' => $preNum,
                'pre_date' => $preDate ?? null,
                'pre_time' => $preTime ?? null,
                'sell_json' => json_encode($sellArr),
                'sell_multi_json' => empty($sellMulti) ? null : json_encode($sellMulti),
                'pay_expire_time' => date('Y-m-d H:i:s', strtotime('+30 minutes')),
                'state' => Order::STATE_WAIT_PAY,
                'created_at' => date('Y-m-d H:i:s'),
            ];
            $orderId = Db::table('order')->insertGetId($data);
            // 消减库存
            DB::commit();
        } catch (Exception $e) {
            DB::rollBack();
            $this->throwBusinessException($e->getMessage());
        }
        // 下单之后支付
        $data['openid'] = User::query()->where(['id' => $uid])->value('openid');
        return $this->pay($uid, $orderId, $data);
    }

    /**
     * 支付
     * @param $uid
     * @param $orderId
     * @param $order
     * @return array|string|void
     * @throws BusinessException
     * @throws GuzzleException
     */
    public function pay($uid, $orderId, $order = [])
    {
        if (empty($order)) {
            $order = Order::query()->where(['id' => $orderId, 'user_id' => $uid])->first(['order_sn', 'pay_price', 'state']);
            if (!$order) {
                $this->throwBusinessException('订单不存在');
            } elseif ($order['state'] != Order::STATE_WAIT_PAY) {
                $this->throwBusinessException('非待支付订单');
            }
            $order = $order->toArray();
            $order['openid'] = User::query()->where(['id' => $uid])->value('openid');
        }
        try {
            $result = WechatService::getInstance()->payment(
                [
                    "out_trade_no" => $order['order_sn'],
                    "description" => '订单支付',
                    "notify_url" => config('app.url') . '/api/order/notify',
                    "amount" => [
                        "total" => env('PAY_TEST') ? 1 : (int)number_format($order['pay_price'] * 100, 0, '.', ''),
                        "currency" => "CNY"
                    ],
                    "payer" => [
                        "openid" => $order['openid'] // <---- 请修改为服务号下单用户的 openid
                    ]
                ]
            );

            return array_merge($result, ['order_id' => $orderId]);
        } catch (Exception $e) {
            $this->throwBusinessException($e->getMessage());
        }
    }

    /**
     * 支付回调
     * @param $params
     * @return true|void
     */
    public function notify($params)
    {
        // 获取数据
        $data = Order::query()->where(['order_sn' => $params['out_trade_no']])->first();
        if ($data && $data->state == Order::STATE_WAIT_PAY) {
            $data->transaction_id = $params['transaction_id'];
            $data->pay_time = date('Y-m-d H:i:s');
            $data->state = Order::STATE_WAIT_USE;
            $data->save();
            // 添加消息
            $sellJson = json_decode($data->sell_json, true);
            NoticeService::getInstance()->add(Notice::TYPE_ORDER, $data->id, $data->user_id, $sellJson['name'] . '购买成功');
            return true;
        }
    }

    /**
     * 订单列表
     * @param $page
     * @param $pageSize
     * @param $uid
     * @param $keyword
     * @param $sellType
     * @param $state
     * @param $filter
     * @return mixed
     */
    public function orderList($page, $pageSize, $uid, $keyword, $sellType, $state, $filter)
    {
        // 设置对象
        $model = Order::query();
        // 关键词
        if ($keyword) {
            $model = $model->where('order_sn|sell_json->name|sell_json->desc', 'like', '%' . $keyword . '%');
        }
        // 售卖类型
        if ($sellType) {
            $model = $model->where(['sell_type' => $sellType]);
        }
        // 订单状态
        if ($state) {
            if ($state == Order::STATE_WAIT_PAY) {
                $model = $model->whereIn('state', [Order::STATE_PAY_EXPIRE, Order::STATE_WAIT_PAY]);
            } elseif ($state == Order::STATE_WAIT_USE) {
                $model = $model->whereIn('state', [Order::STATE_WAIT_USE, Order::STATE_USE_EXPIRE]);
            } elseif ($state == Order::STATE_REFUNDING) {
                $model = $model->whereIn('state', [Order::STATE_REFUNDING, Order::STATE_REFUNDED]);
            } else {
                $model = $model->where(['state' => $state]);
            }
        }
        // 筛选
        if ($filter) {
            $model = $model->where(['state' => $filter]);
        }
        // 获取列表
        $result = $model
            ->where(['user_id' => $uid])
            ->whereNull('user_delete_time')
            ->orderBy('state')
            ->orderBy('id', 'desc')
            ->paginate($pageSize, ['id', 'sell_type', 'sell_id', 'order_sn', 'pay_price', 'sell_json', 'state', 'pay_expire_time'], 'page', $page);

        $result->getCollection()->transform(function ($item) {
            $item = json_decode($item, true);
            $item['sell_json'] = json_decode($item['sell_json'], true);
            $item['sell_json']['img'] = storage($item['sell_json']['img']);
            return $item;
        });

        return $this->successPage($result);
    }

    /**
     * 订单详情
     * @param $uid
     * @param $orderId
     * @return array|mixed[]
     * @throws BusinessException
     */
    public function orderDetail($uid, $orderId)
    {
        // 获取数据
        $data = Order::query()->where(['id' => $orderId, 'user_id' => $uid])->first();
        if (!$data) {
            $this->throwBusinessException('订单不存在');
        }
        $data = $data->toArray();

        // 安全检查及默认赋值
        $data['pay_type_text'] = Order::payTypeMap()[$data['pay_type']] ?? '';

        // 处理 sell_json
        $sellJson = json_decode($data['sell_json'], true);
        if (is_array($sellJson)) {
            $sellJson['img'] = storage($sellJson['img']);
        }
        $data['sell_json'] = $sellJson;

        // 处理 sell_multi_json
        if (!empty($data['sell_multi_json'])) {
            $sellMultiJson = json_decode($data['sell_multi_json'], true);
            if (is_array($sellMultiJson)) {
                foreach ($sellMultiJson as &$item) {
                    $item['img'] = storage($item['img']);
                }
                unset($item); // 断开引用
            } else {
                $sellMultiJson = [];
            }
            $data['sell_multi_json'] = $sellMultiJson;
        }

        $data['state_text'] = Order::stateMap()[$data['state']] ?? '';

        if ($data['state'] == Order::STATE_WAIT_USE) {
            // 初始化 QR service 实例
            $qrCodeService = QrCodeService::getInstance();

            // 构建基础URL参数
            $baseParams = [
                'order_id' => $orderId,
                'sell_id' => $data['sell_id'],
                'sell_type' => $data['sell_type']
            ];

            // 主二维码生成逻辑
            if ($data['sell_type'] == Order::SELL_COMBO) {
                if (!empty($data['sell_multi_json']) && is_array($data['sell_multi_json'])) {
                    foreach ($data['sell_multi_json'] as &$item) {
                        $params = [
                            'order_id' => $orderId,
                            'sell_id' => $item['id'],
                            'sell_type' => $item['sell_type']
                        ];

                        $item['qrcode'] = $qrCodeService->generateQrCode(json_encode($params));
                    }
                }
            } else {
                $data['sell_json']['qrcode'] = $qrCodeService->generateQrCode(json_encode($baseParams));
            }
        }

        return $data;
    }

    /**
     * 再来一单
     * @param $uid
     * @param $orderId
     * @return array
     * @throws BusinessException
     */
    public function orderAgain($uid, $orderId)
    {
        // 获取数据
        $data = Order::query()->where(['id' => $orderId, 'user_id' => $uid])->first();
        if (!$data) {
            $this->throwBusinessException('订单不存在');
        }
        $data = $data->toArray();

        if ($data['sell_type'] == Order::SELL_FOOD) {
            $sellMultiJson = json_decode($data['sell_multi_json'], true);
            $cartJson = [];
            foreach ($sellMultiJson as $item) {
                $cartJson[] = [
                    'food_id' => $item['id'],
                    'num' => $item['num'],
                    'remark' => $item['remark']
                ];
            }
            return ['card_json' => json_encode($cartJson)];
        } else {
            return ['sell_type' => $data['sell_type'], 'sell_id' => $data['sell_id']];
        }
    }

    /**
     * 删除订单
     * @param $uid
     * @param $orderId
     * @return void
     * @throws BusinessException
     */
    public function delOrder($uid, $orderId)
    {
        // 获取数据
        $data = Order::query()->where(['id' => $orderId, 'user_id' => $uid])->first();
        if (!$data) {
            $this->throwBusinessException('订单不存在');
        }

        $data->user_delete_time = date('Y-m-d H:i:s');
        $data->save();
    }

    /**
     * 获取可预约时间
     */
    private function getPreTime($sellType, $sellId, &$price, $type = 1)
    {
        // 可预约时间
//        $preTimeModel = PreTime::query()->where(['status' => BaseModel::STATUS_ENABLE]);
        switch ($sellType) {
            // 租赁
            case Order::SELL_LEASE:
//                $preTimeModel->where(['rel_type' => PreTime::REL_TYPE_LEASE, 'rel_id' => $sellId]);
                $info = Lease::query()->where(['id' => $sellId])->first(['lease_price as price', 'start_time', 'end_time', 'time_slot', 'stock']);
                break;
            // 套餐
            case Order::SELL_COMBO:
//                $preTimeModel->where(['rel_type' => PreTime::REL_TYPE_COMBO, 'rel_id' => $sellId]);
                $info = Combo::query()->where(['id' => $sellId])->first(['combo_price as price', 'start_time', 'end_time', 'time_slot', 'stock']);
                break;
            // 门票
            default :
//                $preTimeModel->where(['rel_type' => PreTime::REL_TYPE_CAMP, 'rel_id' => 1]);
                $info = Camp::query()->where(['id' => $sellId])->first(['camp_price as price', 'start_time', 'end_time', 'stock']);
                break;
        }

        $now = time();
        if (!$info) {
            $this->throwBusinessException(Order::sellTypeMap()[$sellType] . '不存在');
        }

        $endTime = strtotime($info->end_time);
        if ($now > $endTime) {
            $this->throwBusinessException(Order::sellTypeMap()[$sellType] . '预约已结束');
        }

        $price = $info->price ?? 0;
        $stock = $info->stock ?? 0;

        // 直接返回基础信息
        if ($sellType == Order::SELL_CAMP || empty($info->start_time) || empty($info->end_time)) {
            return [];
        }

        $startDate = date('Y-m-d', strtotime($info->start_time));
        $endDate = date('Y-m-d', strtotime($info->end_time));
        $timeSlot = json_decode($info->time_slot, true) ?? [];

        $start = new DateTime($startDate);
        $end = new DateTime($endDate);
        // 创建一个 DateInterval，设置为一天
        $interval = new DateInterval('P1D');
        // 创建一个日期范围对象，用于迭代所有日期
        $dateRange = new DatePeriod($start, $interval, $end);

        // 获取已预约记录
        $alreadyPre = Order::query()
            ->where([
                'sell_type' => $sellType,
                'sell_id' => $sellId
            ])
            ->whereBetween('pre_date', [$startDate, $endDate])
            ->whereIn('state', [Order::STATE_WAIT_PAY, Order::STATE_WAIT_USE])
            ->get(['pre_date', 'pre_time', 'pre_num'])
            ->toArray();

        // 构建已预约数量映射表
        $preNums = [];
        foreach ($alreadyPre as $item) {
            $dates = [$item['pre_date']];
            $times = !empty($timeSlot) ? explode(',', $item['pre_time']) : [''];

            foreach ($dates as $d) {
                foreach ($times as $t) {
                    $key = $d . $t;
                    if (!isset($preNums[$key])) {
                        $preNums[$key] = 0;
                    }
                    $preNums[$key] += $item['pre_num'];
                }
            }
        }

        $dateList = [];
        foreach ($dateRange as $dateObj) {
            $currentDate = $dateObj->format('Y-m-d');
            $isPast = $now >= strtotime($currentDate); // 判断是否过期
            $status = $isPast ? BaseModel::STATUS_DISABLE : BaseModel::STATUS_ENABLE;

            if ($timeSlot) {
                $slotsWithStock = [];
                foreach ($timeSlot as $slot) {
                    $usedCount = $preNums[$currentDate . $slot] ?? 0;
                    $availableStock = max(0, $stock - $usedCount);
                    $slotsWithStock[] = [
                        'time' => $slot,
                        'stock' => $availableStock,
                        'status' => BaseModel::STATUS_ENABLE
                    ];
                }
                $dateList[] = [
                    'date' => $currentDate,
                    'time_slot' => $slotsWithStock,
                    'status' => $status
                ];
            } else {
                $usedCount = $preNums[$currentDate] ?? 0;
                $availableStock = max(0, $stock - $usedCount);
                $dateList[] = [
                    'date' => $currentDate,
                    'stock' => $availableStock,
                    'status' => $status
                ];
            }
        }

        if ($type == 2) {
            return [
                'date_list' => $dateList,
                'start_date' => $startDate,
                'end_date' => $endDate,
                'time_slot' => $timeSlot,
                'stock' => $stock
            ];
        }
        return $dateList;
    }

    /**
     * 检查库存是否充足
     */
    private function checkStock($canPre, $preDate, $preTime, $preNum)
    {
        // 预处理时间戳
        $startDate = isset($canPre['start_date']) ? strtotime($canPre['start_date']) : false;
        $endDate = isset($canPre['end_date']) ? strtotime($canPre['end_date']) : false;
        $preTimestamp = strtotime($preDate);

        if ($preTimestamp < $startDate || $preTimestamp > $endDate) {
            $this->throwBusinessException('日期选择有误');
        }

        if (!isset($canPre['time_slot']) || !in_array($preTime, $canPre['time_slot'])) {
            $this->throwBusinessException('时间段选择有误');
        }

        foreach ($canPre['date_list'] as $v) {
            if (isset($v['time_slot'])) {
                foreach ($v['time_slot'] as $vv) {
                    if ($preTime == $vv['time']) {
                        if ($vv['status'] == BaseModel::STATUS_DISABLE) {
                            $this->throwBusinessException('该时间段不可预约');
                        } elseif ($vv['stock'] < $preNum) {
                            $this->throwBusinessException('该时间段约光了');
                        }
                    }
                }
            } else {
                if ($preDate == $v['date']) {
                    if ($v['status'] == BaseModel::STATUS_DISABLE) {
                        $this->throwBusinessException('该日期不可预约');
                    } elseif ($v['stock'] < $preNum) {
                        $this->throwBusinessException('该日期预约光了');
                    }
                }
            }
        }
    }

    /**
     * 设置套餐详情
     */
    private function setComboCon($comboCon)
    {
        $labelNames = Label::query()->pluck('label_name', 'id') ?? [];
        foreach ($comboCon as &$item) {
            // 根据 sellType 查询售卖对象
            switch ($item['sell_type']) {
                case Combo::SELL_LEASE:
                    $field = ['id', 'lease_name as name', 'lease_desc as desc', 'lease_img as img', 'lease_price as price', 'label_ids'];
                    $result = Lease::query()->where(['id' => $item['sell_id'], 'status' => BaseModel::STATUS_ENABLE])->first($field);
                    break;
                case Combo::SELL_FOOD:
                    $field = ['id', 'food_name as name', 'food_desc as desc', 'food_img as img', 'food_price as price', 'label_ids'];
                    $result = Food::query()->where(['id' => $item['sell_id'], 'status' => BaseModel::STATUS_ENABLE])->first($field);
                    break;
                default:
                    $field = ['id', 'camp_name as name', 'camp_desc as desc', 'camp_img as img', 'camp_price as price', 'label_ids'];
                    $result = Camp::query()->where(['id' => $item['sell_id']])->first($field); // 注意：硬编码 id=1
                    break;
            }
            if (!$result) {
                $this->throwBusinessException(Combo::sellTypeMap()[$item['sell_type']] . '已下架');
            }
            $sellArr = array_merge($result->toArray(), ['sell_type' => $item['sell_type']]);

            $sellArr['img'] = explode(',', $sellArr['img'])[0] ?? '';
            $labelIds = !empty($sellArr['label_ids']) ? explode(',', $sellArr['label_ids']) : [];
            $sellArr['label_name'] = [];
            foreach ($labelIds as $labelId) {
                $sellArr['label_name'][] = $labelNames[$labelId] ?? '';
            }
            $item = $sellArr;
        }

        return $comboCon;
    }

    /**
     * 设置美食列表
     */
    private function setFoodList($foodList)
    {
        $newFoodList = [];
        foreach ($foodList as $val) {
            $val['food_img'] = storageRemove($val['food_img']);
            $newFoodList[] = [
                'id' => $val['id'],
                'name' => $val['food_name'],
                'desc' => $val['food_desc'],
                'img' => $val['food_img'],
                'price' => $val['food_price'],
                'label_ids' => $val['label_ids'],
                'label_name' => $val['label_name'],
                'num' => $val['num'],
                'remark' => $val['remark'],
            ];
        }

        return $newFoodList;
    }
}
